package com.fmdj.vhr.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.map.MapUtil;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.fmdj.common.util.PageUtils;
import com.fmdj.vhr.db.dao.VoucherDao;
import com.fmdj.vhr.db.pojo.VoucherEntity;
import com.fmdj.vhr.service.VoucherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class VoucherServiceImpl implements VoucherService {
    @Autowired
    private VoucherDao voucherDao;

    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public int insert(VoucherEntity entity) {
        return voucherDao.insert(entity);
    }

    @Override
    public PageUtils searchVoucherByPage(Map map) {
        long count = voucherDao.searchVoucherCount(map);
        ArrayList<HashMap> list = null;
        if (count==0) {
            list = new ArrayList<>();
        }else {
            list = voucherDao.searchVoucherByPage(map);
        }
        Integer length = MapUtil.getInt(map, "length");
        Integer start = MapUtil.getInt(map, "start");

        return new PageUtils(list,count,start,length);
    }

    @Override
    @LcnTransaction
    @Transactional
    public int updateVoucherStatus(Map map) {
        int rows = voucherDao.updateVoucherStatus(map);
        if (rows==1) {
            //说明更新状态成功
            //再取出status判断更新的是什么状态 1:上线 2:过期 3:下架
            Integer status = MapUtil.getInt(map, "status");
            long id = MapUtil.getLong(map, "id");
            String uuid = MapUtil.getStr(map, "uuid");

            if (status==1) {
                //上线 将代金卷信息缓存到redis中       为什么缓存到redis:代金卷的使用状态是比较频繁的并且使用redis可以快速查询,效率更高,不使用mysql可以减轻mysql的负载
                HashMap hashMap = voucherDao.searchVoucherById(id);
                //为了后续方便 将hashMap转为bean
                VoucherEntity entity = BeanUtil.toBean(hashMap, VoucherEntity.class); //  将hashMap转为bean hashMap中的键值对应bean的属性
                //具体实现封装在方法中 缓存到redis 使当前方法不显的很臃肿
                saveVoucherCache(entity);
            } else if (status == 3) {
                // 下架 则将redis中对应的缓存删除
                redisTemplate.delete("voucher_info_" + uuid);
                redisTemplate.delete("voucher_" + uuid);
            }
        }
        return rows;
    }



    private void saveVoucherCache(VoucherEntity entity) {
        //缓存到redis中
        String uuid = entity.getUuid();
        HashMap map = new HashMap<>() {{  //封装缓存的参数
            put("totalQuota", entity.getTotalQuota());
            put("discount", entity.getDiscount());
            put("withAmount", entity.getWithAmount());
            put("type", entity.getType());
            put("limitQuota", entity.getLimitQuota());
            put("timeType", entity.getTimeType());
            put("days", entity.getDays());
            put("startTime", entity.getStartTime());
            put("endTime", entity.getEndTime());
        }};
        redisTemplate.opsForHash().putAll("voucher_info_" + uuid, map); //缓存代金卷信息
        redisTemplate.opsForValue().set("voucher_"+uuid,entity.getTotalQuota()); // 缓存代金卷的数量


        //根据代金卷的持续时间 设置代金卷的过期时间
        //从数据库中取出来的时间格式是 2019-09-09 需要转换成 2019-09-09 00:00:00  因为缓存到redis中的时间单位是秒
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); //创建转换的格式
        LocalDateTime startTime = LocalDateTime.parse(entity.getStartTime() + " 00:00:00", formatter);//转换成时间  (别忘了加空格)
        LocalDateTime endTime = LocalDateTime.parse(entity.getEndTime() + " 00:00:00", formatter);

        //利用Duration中的between方法计算两个时间之间的间隔 返回的是Duration对象
        Duration duration = Duration.between(startTime, endTime);
        redisTemplate.expire("voucher_info_" + uuid, duration);
        redisTemplate.expire("voucher_" + uuid, duration);
    }

    @Override
    @LcnTransaction
    @Transactional
    public int deleteVoucherByIds(Long[] ids) {
        //查询所有的代金卷
        ArrayList<HashMap> list = voucherDao.searchVoucherTakeCount(ids);
        ArrayList<Long> temp = new ArrayList<Long>(); //  临时存放要删除的代金卷ID

        //遍历所有的代金卷(每一个代金券相当于一个hashMap)
        list.forEach(one ->{
            Long id = MapUtil.getLong(one, "id");
            String uuid = MapUtil.getStr(one, "uuid");
            Long takeCount = MapUtil.getLong(one, "takeCount");
            Long totalQuota = MapUtil.getLong(one, "totalQuota");

            if (takeCount==0) {
                //判断redis缓存中是否有该代金券
                if (redisTemplate.hasKey("voucher_" + uuid)) {
                    //从redis中获取代金券数量
                    long num = Long.parseLong(redisTemplate.opsForValue().get("voucher_" + uuid).toString());//从redis缓存中获取的代金卷的数量
                    if (totalQuota==num) {
                        //从数据库中获取代金券数量和redis中获取的代金卷数量相等 则说明该代金卷没有被领取 可以删除
                        temp.add(id);
                        redisTemplate.delete("voucher_info_" + uuid);
                        redisTemplate.delete("voucher_" + uuid);
                    }else {
                        //缓存中的数量大于数据库中的数量 则说明该代金券被领取
                        log.debug("id为"+id+"不能删除");
                    }
                }else {
                    //没有则说明该代金卷没有上线 可以删除
                    temp.add(id);
                }
            }else {
                //takeCount不等0说明已经被领取 不能删除
                log.debug("id为"+id+"不能删除");
            }
        });

        //删除代金卷
        if (temp.size()>0) {
            ids = temp.toArray(new Long[temp.size()]); //集合转化成Long类型数组 数组大小为集合大小
            int rows = voucherDao.deleteVoucherByIds(ids);
            return rows;
        }

        return 0;
    }
}
